#include <stdlib.h>
#include <time.h>
#include <exception>
#include <sys/time.h>

#include "boost/smart_ptr.hpp"

#include "cxcore.h"
#include "cv.h"

#include "basic_utils.hh"
#include "face_detect_vj.hh"

//haar(l!)
const int edge_thresh = 15;

const char DEFAULT_PATH_HAAR_CASCADE_FRONTAL_FACE [] = "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_default.xml";


HaarDetector::HaarDetector()
{
    m_cascade = NULL;
    m_color = CV_RGB(0,255,0);
    m_debug = false;
}

int HaarDetector::load(const char *path)
{
    if(!path){
	m_cascade = (CvHaarClassifierCascade*)
	    cvLoad(DEFAULT_PATH_HAAR_CASCADE_FRONTAL_FACE);
    }
    else
	m_cascade = (CvHaarClassifierCascade*) cvLoad(path);
    
    if(!m_cascade)
	return -1;

    return 0;
}


CvRect HaarDetector::detect( IplImage* image,
			     CvSize min_size, 
			     bool do_pyramids )
{

    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* faces;
    int scale = 1;
    struct timeval tm1, tm2;

    if(m_debug){
	gettimeofday(&tm1,NULL);
    }

    /* if the flag is specified, down-scale the input image to get a
       performance boost w/o loosing quality (perhaps) */
    if( do_pyramids ){
	if (!CV_IS_IMAGE(m_pyr2.get())
	    || m_pyr2->width != image->width/2 
	    || m_pyr2->height != image->height/2)
	    m_pyr2.reset(cvCreateImage(cvSize(image->width/2, image->height/2),
				       image->depth, image->nChannels), deleteIplImage);
	cvPyrDown( image, m_pyr2.get(), CV_GAUSSIAN_5x5 );
	scale = 2;

	/* use the fastest variant */
	faces = cvHaarDetectObjects(m_pyr2.get(), m_cascade, storage, 
				    1.2, 1, CV_HAAR_DO_CANNY_PRUNING, 
				    cvSize(min_size.width/scale ,min_size.height/scale));

    }
    else{
	/* use the fastest variant */
	faces = cvHaarDetectObjects( image, m_cascade, storage, 
				     1.2, 1, CV_HAAR_DO_CANNY_PRUNING, 
				     cvSize(min_size.width/scale, min_size.height/scale));
    }

    if(m_debug){
	gettimeofday(&tm2, NULL);
	tm2.tv_sec -= tm1.tv_sec;
	tm2.tv_usec -= tm1.tv_usec;
	std::cout <<"IPS: " << 1./(double)(tm2.tv_sec+(double)tm2.tv_usec/1000000.) <<std::endl;
    }
    
    CvRect big_rect = cvRect(0,0,0,0);
    
    for(int i = 0; i < faces->total; i++ ){
	// extract biggest rectangle only 
	CvRect rect = *(CvRect*)cvGetSeqElem( faces, i);
	rect = cvRect(rect.x*scale, rect.y*scale, 
		      rect.width*scale, rect.height*scale);
	if(big_rect.width*big_rect.height < rect.width*rect.height)
	    big_rect = rect;
	
	if(m_debug){
	    CvPoint p = cvPoint(rect.x,rect.y);
	    cvRectangle(image, p, cvPoint(p.x + rect.width, p.y + rect.height), m_color);
	    
	    std::cout << "Found "<< i<< " : (" << rect.x << ", " << rect.y << "), " << rect.width << " x " << rect.height << std::endl;

// 	    cvNamedWindow("face_detect");
// 	    cvShowImage("face_detect", image);
// 	    cvWaitKey(0);
	}
    }
        
    cvReleaseMemStorage( &storage );

    return big_rect;

}


